package com.cupdata.zicon.jdk7concurrent.chapter2;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Lock  ---  ReentrantLock
 * ReadWriteLock -- ReentrantReadWriteLock   ReadLock  WriteLock
 * 
 * There can be more than
one thread using read operations simultaneously, but only one thread can be using write
operations. When a thread is doing a write operation, there can't be any thread doing
read operations.
 * 
 * @author SunYabing
 *
 */
public class ReadWriteLockTest {

	// @Test
	public static void main(String[] args) {
		PricesInfo pricesInfo = new PricesInfo();
		
//		System.out.println("price1:"+ pricesInfo.getPrice1());
//		pricesInfo.setPrices(3, 6);
//		System.out.println("price1:"+ pricesInfo.getPrice1());

		Reader readers[] = new Reader[8];
		Thread threadsReader[] = new Thread[8];
		for (int i = 0; i < 8; i++) {
			readers[i] = new Reader(pricesInfo);
			threadsReader[i] = new Thread(readers[i]);
			//threadsReader[i].setPriority(i+1);
		}

		Writer writer = new Writer(pricesInfo);
		Thread threadWriter1 = new Thread(writer);		

		threadWriter1.start();	
		//threadWriter1.setPriority(9);
		
		for (int i = 0; i < 8; i++) {
			threadsReader[i].start();
		}
		

	}

}

class PricesInfo {

	private double price1;
	private double price2;
	private ReadWriteLock lock;

	public PricesInfo() {
		price1 = 1.0;
		price2 = 2.0;
		lock = new ReentrantReadWriteLock(false);
	}

	public double getPrice1() {
		lock.readLock().lock();
		double value = this.price1;
		lock.readLock().unlock();
		return value;
	}

	public double getPrice2() {
		lock.readLock().lock();
		double value = this.price2;
		lock.readLock().lock();
		return value;
	}

	public void setPrices(double price1, double price2) {
		System.out.printf("input price2:\n"+price2);
		if (lock.writeLock().tryLock()) {
			lock.writeLock().lock();
			this.price1 = price1;
			this.price2 = price2;			
			lock.writeLock().unlock();
		}
		//System.out.printf("aaa\n"+getPrice2());
		//System.out.printf("bbb\n"+this.price2);
	}

}

class Reader implements Runnable {
	private PricesInfo pricesInfo;

	public Reader(PricesInfo pricesInfo) {
		this.pricesInfo = pricesInfo;
	}

	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.printf("%s: Price 1: %f\n", Thread.currentThread()
					.getName(), pricesInfo.getPrice1());
			System.out.printf("%s: Price 2: %f\n", Thread.currentThread()
					.getName(), pricesInfo.getPrice2());
		}

	}

}

class Writer implements Runnable {
	private PricesInfo pricesInfo;

	public Writer(PricesInfo pricesInfo) {
		this.pricesInfo = pricesInfo;
	}

	@Override
	public void run() {
		for (int i = 0; i < 3; i++) {
			System.out.printf("Writer: Attempt to modify the prices.\n");
			pricesInfo.setPrices(7,  8);
			System.out.printf("Writer: Prices have been modified.\n");			
			try {
				Thread.sleep(2);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
